#include "tlpacket.h"
#include "main.h"
#include "handlers/sessionhandler.h"

#include <QDataStream>
#include <QString>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "crypto/zlibhelper.h"

namespace Packets
{
using namespace std;

    TLPacket::TLPacket(QByteArray &data){
        CreatePkt(data);
    }

    TLPacket::TLPacket(QString &data){
        QByteArray dap = QByteArray::fromHex(data.toAscii());
        CreatePkt(dap);
    }

    TLPacket::TLPacket(pheader head, QByteArray &data){
        CreatePkt(data,&head);
    }

    TLPacket::TLPacket(pheader head, QString &data){
        QByteArray dat = QByteArray::fromHex(data.toAscii());
        CreatePkt(dat,&head);
    }

    void TLPacket::CreatePkt(QByteArray &data, pheader *head)
    {
        _stm.setVersion(QDataStream::Qt_4_8);
        _data=data;

        _buffer.setBuffer(&_data);
        _buffer.open(QBuffer::ReadWrite);
        _stm.setDevice(&_buffer);
        _stm.device()->reset();
        if(head==NULL)
        {
            _stm >>_header.cmd;
            _stm >> _header.size;
        }else{
            _data.insert(0,head->cmd);
            quint16 sz = (((head->size>> 8)) | (head->size << 8));
            _data.insert(1,(char*)&sz,2);
            _header.cmd= head->cmd;
            _header.size=head->size;
        }
    }

    QString TLPacket::StDump()
    {
        return StDump(_data);
    }

    QString TLPacket::StDump(QByteArray &exdata){
       if(_data.isNull()) return QString("<NULL>");
       long int addr;
       unsigned char buffer[20];
       long int cnt;
       long int cnt2;
       QBuffer buff(&exdata);
       buff.open(QBuffer::ReadWrite);
       QDataStream file_in(&buff);
       quint8 cmd;
       file_in >> cmd;
       std::stringstream  cout;
       long n;

       cout << "\n";
       cout << "<";
       if(TL2CMD_NAMES.contains(cmd))
            cout << TL2CMD_NAMES[cmd].toAscii().data();
       else
            cout << TL2CMD_NAMES[Handlers::Both_unhandled].toAscii().data();

       cout << "{0x" << setfill('0') << setw(2) << hex << (int)cmd << "}";
       quint16 sizz;
       file_in >> sizz;
       file_in.device()->reset();

       cout << " : " << sizz << ">\n";
       cout << "Address               Hexadecimal values                      ASCII\n";
       cout << "-------  -----------------------------------------------  ----------------\n";
     //
     //  Dump the file contents.
     //
       addr = 0;

       while ( 1 )
       {
         cnt = file_in.readRawData( ( char * ) buffer, 16 );

         if ( cnt <= 0 )
         {
           break;
         }
     //
     //  Print the address in decimal and hexadecimal.
     //
         cout << setfill('0') << setw(7) << hex << ( int ) addr << "  ";

         addr = addr + 16;
     //
     //  Print 16 data items, in pairs, in hexadecimal.
     //
         cnt2 = 0;
         for ( n = 0; n < 16; n++ )
         {
           cnt2 = cnt2 + 1;
           if ( cnt2 <= cnt )
           {
             cout << uppercase << hex << setw(2) << setfill ( '0' ) << ( int ) buffer[n];
           }
           else
           {
             cout << "  ";
           }
           cout << " ";
         }

         cout << setfill ( ' ' );
     //
     //  Print the printable characters, or a period if unprintable.
     //
         cout << " ";
         cnt2 = 0;
         for ( n = 0; n < 16; n++ )
         {
           cnt2 = cnt2 + 1;
           if ( cnt2 <= cnt )
           {
             if ( buffer[n] < 32 || 126 < buffer[n] )
             {
               cout << '.';
             }
             else
             {
               cout << buffer[n];
             }
           }
         }
         cout << "\n";
         cout << dec;

         if ( file_in.atEnd() )
         {
           break;
         }

       }
     //
     // Close the file.
     //
       QString result(cout.str().c_str());
       //delete[] buffer;
       return result;
   }

    void TLPacket::AddCompressData(QByteArray &data)
    {
        AddZdata(data);
    }
    void TLPacket::AddCompressData(void* data, int size)
    {
        QByteArray buf((char*)data,size);
        AddZdata(buf);
    }
    void TLPacket::AddCompressData(QString &data)
    {
        QByteArray dap = QByteArray::fromHex(data.toAscii());
        AddZdata(dap);
    }

    void TLPacket::AddZdata(QByteArray &data)
    {
        ZLibHelper::Compress(&data);
        _stm.device()->seek(_stm.device()->size());
        _stm << (quint16)(((data.size()>> 8)) | (data.size() << 8));
        _data.append(data);
        _stm.device()->seek(1);
        _stm <<(quint16)(_stm.device()->size()-3);
    }
}
